﻿// Copyright (c) 2012 - 2021 Jared Zheng <jaredz at outlook dot com>
// Buddha Framework is licensed under Mulan PSL v2.
// You can use this software according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of Mulan PSL v2 at:
//          http://license.coscl.org.cn/MulanPSL2
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
// See the Mulan PSL v2 for more details.
//
// Create : 2012-12-01 version 0.1 Jared Zheng <jaredz at outlook dot com>
// Update : 2021-03-19 version 4.0.0 Jared Zheng <jaredz at outlook dot com>

#ifndef __COMMON_PACKET_INL__
#define __COMMON_PACKET_INL__

#pragma once

///////////////////////////////////////////////////////////////////////////////////////////////////////////
// CTPAKStream
template <typename TPAK>
INLINE CTPAKStream<TPAK>::CTPAKStream(void)
: CTPAKStreamBase<TPAK>()
{
#ifdef __RUNTIME_DEBUG__
    typename TConvertCheck<TPAK, CPAKHeadBase>::TAG tag = ConvertibleTag();
    tag.Check();
#endif
}

template <typename TPAK>
INLINE CTPAKStream<TPAK>::CTPAKStream(UEVENT uEvent, URANK uRank, USID uSid, UDATA uData)
: CTPAKStreamBase<TPAK>()
{
#ifdef __RUNTIME_DEBUG__
    typename TConvertCheck<TPAK, CPAKHeadBase>::TAG tag = ConvertibleTag();
    tag.Check();
#endif
    TPAK::Reset(uEvent, uRank, uSid, uData);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////
// 通用同步数据包
INLINE CPAKSync::CPAKSync(UEVENT uEvent, URANK uRank, USID uSid, UDATA uData)
: CPAKHeadBase(uEvent, uRank, uSid, uData)
{
}

INLINE CPAKSync::~CPAKSync(void)
{
}

INLINE CPAKSync::CPAKSync(const CPAKSync& aSrc)
: CPAKHeadBase(aSrc)
, m_Status(aSrc.m_Status)
{
}

INLINE CPAKSync& CPAKSync::operator=(const CPAKSync& aSrc)
{
    if (&aSrc != this)
    {
        CPAKHeadBase::operator=(aSrc);
        m_Status = aSrc.m_Status;
    }
    return (*this);
}

INLINE size_t CPAKSync::Length(void) const
{
    return (sizeof(SERVER_STATUS) + CPAKHeadBase::Length());
}

INLINE void CPAKSync::Serialize(CStream& Stream)
{
    CPAKHeadBase::Serialize(Stream);
    if (Stream.IsRead())
    {
        Stream.Read(&m_Status, sizeof(SERVER_STATUS));
    }
    else
    {
        Stream.Write(&m_Status, sizeof(SERVER_STATUS));
    }
}

INLINE SERVER_STATUS& CPAKSync::GetStatus(void)
{
    return m_Status;
}

INLINE void CPAKSync::SetStatus(SERVER_STATUS& ss)
{
    m_Status = ss;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////
// 通用ID数据包
INLINE CPAKID::CPAKID(UEVENT uEvent, URANK uRank, USID uSid, UDATA uData)
: CPAKHeadBase(uEvent, uRank, uSid, uData)
, m_ullId(0)
{
}

INLINE CPAKID::~CPAKID(void)
{
}

INLINE CPAKID::CPAKID(const CPAKID& aSrc)
: CPAKHeadBase(aSrc)
, m_ullId(aSrc.m_ullId)
{
}

INLINE CPAKID& CPAKID::operator=(const CPAKID& aSrc)
{
    if (&aSrc != this)
    {
        CPAKHeadBase::operator=(aSrc);
        m_ullId = aSrc.m_ullId;
    }
    return (*this);
}

INLINE size_t CPAKID::Length(void) const
{
    return (sizeof(ULLong) + CPAKHeadBase::Length());
}

INLINE void CPAKID::Serialize(CStream& Stream)
{
    CPAKHeadBase::Serialize(Stream);
    if (Stream.IsRead())
    {
        Stream >> m_ullId;
    }
    else
    {
        Stream << m_ullId;
    }
}

INLINE ULLong CPAKID::GetId(void)
{
    return m_ullId;
}

INLINE void CPAKID::SetId(ULLong ullId)
{
    m_ullId = ullId;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////
// 通用SRV数据包
INLINE CPAKSRV::CPAKSRV(UEVENT uEvent, URANK uRank, USID uSid, UDATA uData)
: CPAKID(uEvent, uRank, uSid, uData)
, m_ullSrvId(0)
{
}

INLINE CPAKSRV::~CPAKSRV(void)
{
}

INLINE CPAKSRV::CPAKSRV(const CPAKSRV& aSrc)
: CPAKID(aSrc)
, m_ullSrvId(aSrc.m_ullSrvId)
{
}

INLINE CPAKSRV& CPAKSRV::operator=(const CPAKSRV& aSrc)
{
    if (&aSrc != this)
    {
        CPAKID::operator=(aSrc);
        m_ullSrvId = aSrc.m_ullSrvId;
    }
    return (*this);
}

INLINE size_t CPAKSRV::Length(void) const
{
    return (sizeof(ULLong) + CPAKID::Length());
}

INLINE void CPAKSRV::Serialize(CStream& Stream)
{
    CPAKID::Serialize(Stream);
    if (Stream.IsRead())
    {
        Stream >> m_ullSrvId;
    }
    else
    {
        Stream << m_ullSrvId;
    }
}

INLINE ULLong CPAKSRV::GetSrvId(void)
{
    return m_ullSrvId;
}

INLINE void CPAKSRV::SetSrvId(ULLong ullSrvId)
{
    m_ullSrvId = ullSrvId;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////
// 通用数据包解析
INLINE CPAKHeadBase* CommonPacket::Create(CStream& Stream, UEVENT& uEvent)
{
    CStreamSeekScope scope(Stream);
    CPAKHeadBase* pPak = nullptr;

    uEvent = 0;
    Stream >> uEvent;
    switch (uEvent)
    {
    case PAKE_LINK:
    case PAKE_UPDATE:
        {
            pPak = MNEW CNETHead;
        }
        break;
    case PAKE_SYNCACK:
        {
            pPak = MNEW CNETSync;
        }
        break;
    case PAKE_LIVE:
    case PAKE_LIVEACK:
    case PAKE_LINKACK:
    case PAKE_UPDATEACK:
    case PAKE_SYNC:
    case PAKE_UNLINK:
    case PAKE_UNLINKACK:
        {
            pPak = MNEW CPAKHead;
        }
        break;
    default:
        {
            if ((uEvent >= PAKE_SRV_BEGIN) && (uEvent <= PAKE_SRV_END))
            {
                pPak = MNEW CNETSRV;
            }
            else if ((uEvent >= PAKE_ID_BEGIN) && (uEvent <= PAKE_ID_END))
            {
                pPak = MNEW CNETID;
            }
            else
            {
                pPak = MNEW CNETHead;
            }
        }
    }
    return pPak;
}

INLINE bool CommonPacket::ReadString(CStream& Stream, CString& str, SizeLen sMaxLen)
{
    assert(Stream.IsRead());
    SizeLen sLen = 0;
    Stream >> sLen;
    if (sLen >= sMaxLen)
    {
        return false;
    }
    SeekPos sPos = (0 - (SeekPos)sLen);
    Stream.Seek(sPos, SEEKO_CURRENT);
    Stream >> str;
    return true;
}

#endif // __COMMON_PACKET_INL__
